home *** CD-ROM | disk | FTP | other *** search
- /*
- ** $VER: TeeHandler.c 1.40 (17th December 1997)
- */
- #include <exec/types.h>
- #include <exec/tasks.h>
- #include <exec/ports.h>
- #include <exec/memory.h>
- #include <dos/dos.h>
- #include <dos/dosextens.h>
- #include <dos/filehandler.h>
- #include <clib/exec_protos.h>
- #include <clib/dos_protos.h>
-
-
- /* Program Information */
- #define PROG_NAME "tee-handler"
- #define PROG_VER "1"
- #define PROG_REV "40"
- #define PROG_DATE "17th December 1997"
-
- /* Version String */
- const char VerStr[] = "\0$VER: "PROG_NAME" "PROG_VER"."PROG_REV" ("PROG_DATE")\r\n";
-
-
- #ifdef DEBUG
-
- /* Prototypes for debug.lib functions */
- extern __stkargs void kputs(STRPTR string);
- extern __stkargs void kprintf(STRPTR format, ... );
-
-
- /* Strings associated with actions known by this handler */
- STRPTR Actions[] = {"ACTION_FINDUPDATE",
- "ACTION_FINDOUTPUT",
- "ACTION_SEEK",
- "ACTION_WRITE",
- "ACTION_END",
- "ACTION_IS_FILESYSTEM"};
-
- /*
- ** KPrint a string indicating packet type.
- */
- __regargs void KPutPacketName(LONG Type)
- {
- int i;
-
- switch (Type) {
- case ACTION_FINDUPDATE: i = 1; break;
- case ACTION_FINDOUTPUT: i = 2; break;
- case ACTION_SEEK: i = 3; break;
- case ACTION_WRITE: i = 4; break;
- case ACTION_END: i = 5; break;
- case ACTION_IS_FILESYSTEM: i = 6; break;
- default: i = 0;
- }
- if (i) kprintf("TeeHandler: Got an %s packet.\n\n",Actions[i-1]);
- else kprintf("TeeHandler: Got an Unknown packet (%ld).\n\n",Type);
- }
-
- #endif
-
-
- /*
- ** Convert a BString to a CString.
- ** String must be duplicated if you wish to keep it.
- */
- __regargs STRPTR b2cstr(BSTR bstring)
- {
- #ifdef DEBUG
- kputs (" TeeHandler: b2cstr() Called:\n");
- kprintf(" BString = \"%b\"\n",bstring);
- #endif
-
- static char cstring[255];
- STRPTR realbstr;
- UBYTE len;
- int i;
-
- realbstr = (STRPTR)BADDR(bstring);
- len = realbstr[0];
-
- for (i=0; i<len; i++)
- cstring[i] = realbstr[i+1];
- cstring[i] = '\0';
-
- #ifdef DEBUG
- kprintf(" CString = \"%s\"\n",cstring);
- kputs (" TeeHandler: b2cstr() Finished.\n\n");
- #endif
-
- return cstring;
- }
-
- /*
- ** Get a pointer to the Process that sent the packet.
- */
- #define FindPktProc(pkt) \
- ((struct Process *)((UBYTE *)(pkt)->dp_Port - sizeof(struct Task)))
-
-
- struct TeeArgs {
- ULONG ArgC;
- STRPTR *ArgV;
- };
-
- /*
- ** Parse a given Argument String into C-style ArgC/ArgV.
- ** Format of TeeHandler Arguments:
- ** <DOSDEV>:<Arg1>,<Arg2>,...,<ArgN> ; "\," ==> ","
- */
- __regargs struct TeeArgs *ParseArgs(STRPTR ArgS)
- {
- #ifdef DEBUG
- kputs (" TeeHandler: ParseArgs() Called.\n");
- #endif
-
- struct TeeArgs *teeArgs;
- STRPTR *ArgV;
- STRPTR Strings;
- ULONG ArgC;
- ULONG CharC;
- int i,j,k,l;
-
-
- /* Count the number of Arguments and Characters */
-
- /* First for DOSDEV: ... */
- for (i=0; ArgS[i] != ':'; i++)
- ;
- i++;
- ArgC = 1;
- CharC = i;
-
- /* Then for the rest of the Arguments */
- for (j=i; ArgS[j] != '\0'; j++)
- {
- if (ArgS[j] == ',')
- ArgC++;
- else if (ArgS[j] == '\\')
- j++;
-
- CharC++;
- }
- ArgC++;
-
- /* Add two NULL byte for DeviceName: and last argument (no commas) */
- CharC += 2;
-
- /* Allocate memory for ArgC string pointers */
- /* = sizeof(teeArgs) + ArgC*4 + CharC */
- teeArgs = (struct TeeArgs *)
- AllocVec(sizeof(struct TeeArgs) + (ArgC<<2) + CharC, NULL);
- if (!teeArgs)
- /* Oh dear, no memory ... Shall we try it with individual */
- /* allocations? Why bother? CRASH AND BURN, HA HA HA HA!! */
- return NULL;
-
- /* So a map of our memory block would be: */
- /* struct TeeArgs { */
- /* ULONG ArgC; */
- /* STRPTR *ArgV; */
- /* }; */
- /* STRPTR ArgV[ArgC]; */
- /* "DeviceName:",0 */
- /* "Arg1",0 */
- /* "Arg2",0 */
- /* ... */
- /* "ArgN",0 (where N == ArgC-1) */
-
- /* Link it all together ... */
- teeArgs->ArgC = ArgC;
- ArgV = (STRPTR *)((UBYTE *)teeArgs + sizeof(struct TeeArgs));
- teeArgs->ArgV = ArgV;
- Strings = (STRPTR)((UBYTE *)ArgV + (ArgC<<2));
- ArgV[0] = Strings;
-
- /* i indicates the current position in the ArgS string */
- /* j incicates the current position in the Strings memory block */
- /* k indicates the current argument */
- /* l indicates the start of the current argument */
-
- /* Copy device name */
- for (i=0, j=0; ArgS[i] != ':'; i++, j++)
- Strings[j] = ArgS[i];
- Strings[j++] = ':'; i++;
- Strings[j++] = '\0';
-
- /* Copy arguments */
- for (k=1,l=j; ArgS[i] != '\0'; i++,j++)
- {
- if (ArgS[i] == ',')
- {
- Strings[j] = '\0';
-
- ArgV[k++] = Strings+l;
- l = j+1;
- }
- else if (ArgS[i] == '\\')
- Strings[j] = ArgS[++i];
- else
- Strings[j] = ArgS[i];
- }
- Strings[j] = '\0';
- ArgV[k] = Strings+l;
-
- /* Well, that should do it... */
- #ifdef DEBUG
- kputs (" TeeHandler: ParseArgs() Finished.\n\n");
- #endif
- return teeArgs;
- }
-
-
- /*
- ** Delete the entire TeeArgs structure and associated fields.
- */
- __regargs void DeleteArgs(struct TeeArgs *teeArgs)
- {
- #ifdef DEBUG
- kputs (" TeeHandler: DeleteArgs() Called.\n");
- #endif
-
- /* Because this was allocated in one big block, */
- /* we can release it all with just one call */
- FreeVec((APTR)teeArgs);
-
- #ifdef DEBUG
- kputs (" TeeHandler: DeleteArgs() Finished.\n\n");
- #endif
- }
-
-
- /*
- ** Perform WaitPkt() with a port other than pr_MsgPort.
- */
- __regargs struct DosPacket *WaitPktPort(struct MsgPort *port)
- {
- struct Message *msg;
-
- WaitPort(port);
- msg = GetMsg(port);
- return (struct DosPacket *)msg->mn_Node.ln_Name;
- }
-
- /*
- ** Perform ReplyPkt() with a port other then pr_MsgPort.
- */
- __regargs void ReplyPktPort(struct MsgPort *port,
- struct DosPacket *dp, LONG Res1, LONG Res2)
- {
- struct MsgPort *rport = dp->dp_Port;
-
- dp->dp_Res1 = Res1;
- dp->dp_Res2 = Res2;
- dp->dp_Port = port;
-
- PutMsg(rport,dp->dp_Link);
- }
-
-
- struct DOSLibrary *DOSBase;
-
- /*
- ** Entry Point
- */
- __stkargs int _main(int len, char *args)
- {
- struct TeeArgs *teeArgs;
- ULONG ArgC;
- STRPTR *ArgV;
- BPTR *OutputFiles; /* [0] = StdOutFile, [1..n] = OutputFiles */
-
- struct DosPacket *packet;
- struct MsgPort *teePort;
- struct DeviceNode *teeDevNode;
- struct Process *teeProc;
- struct Process *callProc;
- struct FileHandle *teeFileHandle;
-
- ULONG running = TRUE;
- ULONG opencnt = 0;
- LONG rc = DOSTRUE, rc2 = 0;
- int i;
-
-
- #ifdef DEBUG
- kputs ("TeeHandler Started.\n\n");
- #endif
-
- /* Get this process and attempt to open DOS Library v36+ */
- teeProc = (struct Process *)FindTask(NULL);
- DOSBase = (struct DOSLibrary *)OpenLibrary("dos.library",36);
- if (!DOSBase)
- /* Maybe an alert here to inform the good user that s/he's using */
- /* an obsolete operating system? */
- return RETURN_FAIL;
-
- /* Wait for the startup packet */
- #ifdef DEBUG
- kputs("TeeHandler: Waiting for startup packet...\n\n");
- #endif
- packet = WaitPktPort(&teeProc->pr_MsgPort);
-
- /* Got the startup packet, now initialise it and reply */
- /* dp_Arg1 ==> (BSTR) Mount Name (ie Mount TEE:) */
- /* dp_Arg3 ==> (BPTR) Device Node */
-
- /* Create a new MsgPort so we don't confuse the dos.library */
- teePort = CreateMsgPort();
- if (!teePort)
- {
- /* No memory? No signal? */
- CloseLibrary((struct Library *)DOSBase);
- rc = FALSE;
- rc2 = ERROR_OBJECT_NOT_FOUND;
- }
-
- teeDevNode = (struct DeviceNode *)BADDR(packet->dp_Arg3);
- teeDevNode->dn_Task = teePort;
- ReplyPktPort(teePort,packet,rc,rc2);
- if (rc2)
- return RETURN_FAIL;
-
- /* Main Loop */
- #ifdef DEBUG
- kputs("TeeHandler: Starting Main Loop\n");
- #endif
- while (running)
- {
- /* Wait for an action packet */
- #ifdef DEBUG
- kputs("TeeHandler: Waiting for action packet...\n");
- #endif
- packet = WaitPktPort(teePort);
- #ifdef DEBUG
- KPutPacketName(packet->dp_Type);
- #endif
-
- /* Got an action packet. */
- switch (packet->dp_Type)
- {
- /*******************************************************************/
-
- case ACTION_FINDUPDATE:
- case ACTION_FINDOUTPUT:
- /* Setup for output (eg Open("TEE:",MODE_OLDFILE)) */
- /* dp_Arg1 = (BPTR) File Handle */
- /* dp_Arg3 = (BSTR) Access Name (eg Dir >TEE:T:bla) */
-
- opencnt++; /* We have another user! */
-
- #ifdef DEBUG
- kprintf(" Argument String = \"%b\"\n\n",packet->dp_Arg3);
- #endif
- teeArgs = ParseArgs(b2cstr((BSTR)packet->dp_Arg3));
- if (!teeArgs)
- {
- /* Aww, no memory */
- if (!(--opencnt)) running = FALSE;
- rc = FALSE;
- rc2 = ERROR_NO_FREE_STORE;
-
- break;
- }
- ArgC = teeArgs->ArgC;
- ArgV = teeArgs->ArgV;
-
- /* Now Allocate some memory for the Output Files Array */
- /* = ArgC + 2 (StdOut and -1 End Marker) */
- OutputFiles = (BPTR *)AllocVec( (ArgC+2)<<2 ,MEMF_CLEAR);
- if (!OutputFiles)
- {
- /* No Memory! */
- DeleteArgs(teeArgs);
- if (!(--opencnt)) running = FALSE;
- rc = FALSE;
- rc2 = ERROR_NO_FREE_STORE;
-
- break;
- }
-
- /* Save the caller's Output and change to it's CurrentDir */
- callProc = FindPktProc(packet);
- OutputFiles[0] = callProc->pr_COS;
- CurrentDir(callProc->pr_CurrentDir);
- #ifdef DEBUG
- struct CommandLineInterface *CLI = (struct CommandLineInterface *)
- BADDR(callProc->pr_CLI);
-
- kprintf(" Calling Process: 0x%08lx\n",callProc);
- kprintf(" Task Name: %s\n",callProc->pr_Task.tc_Node.ln_Name);
- if (CLI)
- kprintf(" CommandName: %b\n",CLI->cli_CommandName);
- kprintf(" Output Stream: 0x%08lx\n\n",OutputFiles[0]);
- #endif
-
- /* Open each of our Output files */
- for (i=1; i < ArgC; i++)
- {
- #ifdef DEBUG
- kprintf(" OutputName = \"%s\"\n",ArgV[i]);
- #endif
- if (ArgV[i][0] != '\0')
- OutputFiles[i] = Open(ArgV[i],packet->dp_Type);
-
- #ifdef DEBUG
- kprintf(" OutputFile Handle = 0x%08lx\n\n",OutputFiles[i]);
- #endif
- }
- /* Set the last field to -1 */
- OutputFiles[ArgC] = -1;
-
- /* Set the file handle's relevent items */
- teeFileHandle = (struct FileHandle *)BADDR(packet->dp_Arg1);
- teeFileHandle->fh_Port = (struct MsgPort *)DOSTRUE;
- teeFileHandle->fh_Args = (LONG)teeFileHandle;
- teeFileHandle->fh_Arg2 = (LONG)OutputFiles;
-
- /* Get rid of the Arguments */
- DeleteArgs(teeArgs);
-
- break;
-
- /*******************************************************************/
-
- case ACTION_SEEK:
- /* Perform Seek Action (eg Seek(TeeFile, Position, Offset)) */
- /* dp_Arg1 = File Handle's fh_Args (set by ACTION_FIND... ) */
- /* dp_Arg2 = (LONG) Position to move to, based on offset. */
- /* dp_Arg3 = (LONG) Offset: Start or End of file or current pos */
-
- #ifdef DEBUG
- int t = packet->dp_Arg3;
-
- kprintf(" Offset Position: %s+(%ld).\n\n",
- (t ? (t < 0 ? "Start" : "End") : "Current"),
- packet->dp_Arg2);
- #endif
-
- teeFileHandle = (struct FileHandle *)packet->dp_Arg1;
- OutputFiles = (BPTR *)teeFileHandle->fh_Arg2;
-
- for (i=1; OutputFiles[i] != -1; i++)
- if (OutputFiles[i])
- Seek(OutputFiles[i],packet->dp_Arg2,packet->dp_Arg3);
-
- break;
-
- /*******************************************************************/
-
- case ACTION_WRITE:
- /* Perform write actions (eg Write(TeeFile, buffer, bufsize)) */
- /* dp_Arg1 = File Handle's fh_Args (set by ACTION_FIND... ) */
- /* dp_Arg2 = (APTR) Pointer to buffer to write */
- /* dp_Arg3 = (ULONG) Number of bytes to write */
-
- #ifdef DEBUG
- kprintf(" Writing %ld bytes.\n\n",packet->dp_Arg3);
- #endif
-
- teeFileHandle = (struct FileHandle *)packet->dp_Arg1;
- OutputFiles = (BPTR *)teeFileHandle->fh_Arg2;
- rc = packet->dp_Arg3;
-
- for (i=0; OutputFiles[i] != -1; i++)
- if (OutputFiles[i])
- Write(OutputFiles[i],(APTR)packet->dp_Arg2,rc);
-
- break;
-
- /*******************************************************************/
-
- case ACTION_END:
- /* Reverse actions taken by ACTION_FIND* ... */
- /* dp_Arg1 = File Handle's fh_Args (set by ACTION_FIND... ) */
-
- teeFileHandle = (struct FileHandle *)packet->dp_Arg1;
- OutputFiles = (BPTR *)teeFileHandle->fh_Arg2;
-
- for (i=1; OutputFiles[i] != -1; i++)
- if (OutputFiles[i])
- Close(OutputFiles[i]);
-
- FreeVec((APTR)OutputFiles);
-
- if (!(--opencnt)) running = FALSE;
- break;
-
- /*******************************************************************/
-
- case ACTION_IS_FILESYSTEM:
- /* Is this a FileSystem? Erm ... Nope. Sorry. */
-
- rc = FALSE;
- /* rc2 = 0 */
-
- break;
-
- /*******************************************************************/
-
- default:
- /* All other packets dock here */
-
- rc = FALSE;
- rc2 = ERROR_ACTION_NOT_KNOWN;
-
- /* break; */
-
- /*******************************************************************/
- }
-
- /* Reply back to the calling Process */
- ReplyPktPort(teePort,packet,rc,rc2);
- }
-
- /* Now we close up and exit */
- #ifdef DEBUG
- kputs("TeeHandler Shutting Down.\n\n\n");
- #endif
- teeDevNode->dn_Task = NULL;
- DeleteMsgPort(teePort);
- CloseLibrary((struct Library *)DOSBase);
-
- return RETURN_OK;
- }
-